use std::{
    fmt::{Debug, Display},
    rc::Rc,
};

use super::{interpreter::Interpreter, object::Object, syntaxResult::SyntaxResult};

pub trait SyntaxCallable {
    fn Call(
        &self,
        _interpreter: &Interpreter,
        _arguments: Vec<Object>,
    ) -> Result<Object, SyntaxResult>;
    fn arity(&self) -> usize;
    fn toString(&self) -> String;
}

#[derive(Clone)]
pub struct Callable {
    pub func: Rc<dyn SyntaxCallable>,
}

impl Debug for Callable {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        //f.debug_struct("Callable").field("func", &self.func).finish()
        write!(f, "{}", self.toString())
    }
}

impl Display for Callable {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.toString())
    }
}
impl PartialEq for Callable {
    fn eq(&self, other: &Self) -> bool {
        Rc::ptr_eq(&self.func, &other.func)
    }
}
impl SyntaxCallable for Callable {
    fn Call(
        &self,
        _interpreter: &Interpreter,
        _arguments: Vec<Object>,
    ) -> Result<Object, SyntaxResult> {
        self.func.Call(_interpreter, _arguments)
    }

    fn arity(&self) -> usize {
        self.func.arity()
    }

    fn toString(&self) -> String {
        self.func.toString()
    }
}
